<?php

namespace app\pay\controller;

use think\facade\Db;
use AopSDK\request\AlipayTradeCreateRequest;
use AopSDK\request\AlipaySystemOauthTokenRequest;
use Wxpay\lib\WxPayCloseOrder;
use Wxpay\lib\WxPayMicroPay;
use Wxpay\lib\WxPayOrderQuery;
use Wxpay\WxPayConfig;
use Wxpay\JsApiPay;
use Wxpay\lib\WxPayUnifiedOrder;
use Wxpay\lib\WxPayApi;
use Jssdk\jssdk;

class Codepay
{
    public function dopay()
    {
        $shop_id = input('shop_id', 0, 'intval');
        $code = input('code', '', 'trim');
        $remark = input('remark', '', 'trim');
        $total_fee = input('total_fee', 0, 'trim');
        $total_fee = intval(floatval($total_fee) * 100) / 100;
        if(empty($shop_id) || empty($code) || empty($total_fee)) {
            return errorJson('参数错误');
        }
        $shop = Db::name('shop')
            ->where('id', $shop_id)
            ->find();

        $num = substr($code, 0, 2);
        if ($num >= 25 && $num <= 30) { //支付宝付款码支付
            $pay_type = 'alipay';
        } else if ($num >= 10 && $num <= 15) { //微信的付款码支付
            $pay_type = 'wxpay';
        } else {
            return errorJson('请扫描微信或支付宝付款码');
        }
        $out_trade_no = $this->createOrderNo($pay_type);
        $order_id = Db::name('order')->insertGetId([
            'agent_id' => $shop['agent_id'],
            'shop_id' => $shop_id,
            'qrcode_id' => 0,
            'user_id' => '',
            'out_trade_no' => $out_trade_no,
            'transaction_id' => '',
            'total_fee' => $total_fee * 100,
            'order_type' => 'pay',
            'pay_type' => $pay_type,
            'remark' => $remark,
            'status' => 0, // 0-待付款；1-成功；2-失败
            'add_time' => time()
        ]);

        if($order_id) {
            if($pay_type == 'alipay') {
                $payConfig = getShopPayConfig($shop, 'alipay');
                if (empty($payConfig)) {
                    return errorJson('未开通支付宝支付');
                }
                $this->alipay();

            } elseif ($pay_type == 'wxpay') {
                $this->wxpay($out_trade_no, $shop, $code, $total_fee);
            } else {
                return errorJson('不支持的付款码');
            }
        }

    }

    /**
     * 微信支付
     */
    private function wxpay($out_trade_no, $shop, $code, $total_fee)
    {
        $payConfig = getShopPayConfig($shop, 'wxpay');
        if (empty($payConfig)) {
            return errorJson('未开通微信支付');
        }

        $config = new WxPayConfig();
        $config->SetAppId($payConfig['appid']);
        $config->SetAppSecret($payConfig['appsecret']);
        $config->SetMerchantId($payConfig['mch_id']);
        if ($payConfig['type'] == 'server') {
            $config->SetSubMchID($payConfig['sub_mch_id']);
        }
        $config->SetKey($payConfig['key']);
        $config->SetSignType('HMAC-SHA256');

        $input = new WxPayMicroPay();
        $input->SetOut_trade_no($out_trade_no);
        $input->SetTotal_fee($total_fee * 100);
        $input->SetAuth_code($code);
        $input->SetBody('扫码收款');
        $input->SetAttach('扫码收款');
        $input->SetTime_start(date('YmdHis'));
        $input->SetTime_expire(date('YmdHis', time() + 600));
        if ($payConfig['type'] == 'server') {
            $input->SetSubMchID($payConfig['sub_mch_id']);
        }

        $WxPayApi = new WxPayApi();
        $result = $WxPayApi->micropay($config, $input);

        file_put_contents("./wxpay_result.txt", json_encode($result));

        if (!empty($result) && $result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
            $this->wxpaySuccess($out_trade_no, $payConfig, $shop, $result);
        } else if (!empty($result) && $result['err_code'] == 'USERPAYING' && $result['return_code'] == 'SUCCESS' && $result['return_msg'] == 'OK') {
            // 用户支付中
            $this->wxpayOrderQuery($out_trade_no, $payConfig, $shop);
        } else {
            $this->wxpayFail($out_trade_no);
        }
    }

    /**
     * 轮询用户支付状态
     */
    private function wxpayOrderQuery($out_trade_no, $payConfig, $shop)
    {
        $input = new WxPayOrderQuery();
        $input->SetOut_trade_no($out_trade_no);
        if ($payConfig['type'] == 'server') {
            $input->SetSubMchID($payConfig['sub_mch_id']);
        }

        $config = new WxPayConfig();
        $config->SetAppId($payConfig['appid']);
        $config->SetAppSecret($payConfig['appsecret']);
        $config->SetMerchantId($payConfig['mch_id']);
        if ($payConfig['type'] == 'server') {
            $config->SetSubMchID($payConfig['sub_mch_id']);
        }
        $config->SetKey($payConfig['key']);
        $config->SetSignType('HMAC-SHA256');

        $WxPayApi = new WxPayApi();
        $result = $WxPayApi->orderQuery($config, $input);

        if ($result['trade_state'] == 'USERPAYING' || $result['trade_code'] == 'USERPAYING') {
            // 用户支付中
            $runtime = $this->getRunTime();
            if ($runtime < 60) {
                usleep(1500000);
                $this->wxpayOrderQuery($out_trade_no, $payConfig, $shop);
            } else {
                // 撤销订单
                $this->wxpayCloseOrder($out_trade_no, $payConfig);
            }
        } elseif ($result['trade_state'] == 'SUCCESS' || $result['trade_code'] == 'SUCCESS') {
            // 支付成功
            $this->wxpaySuccess($out_trade_no, $payConfig, $shop, $result);
        } else {
            // 支付失败
            $this->wxpayFail($out_trade_no, ['return_msg' => '用户取消支付']);
        }
    }

    private function wxpayCloseOrder($out_trade_no, $payConfig)
    {
        $input = new WxPayCloseOrder();
        $input->SetOut_trade_no($out_trade_no);
        if ($payConfig['type'] == 'server') {
            $input->SetSubMchID($payConfig['sub_mch_id']);
        }

        $config = new WxPayConfig();
        $config->SetAppId($payConfig['appid']);
        $config->SetAppSecret($payConfig['appsecret']);
        $config->SetMerchantId($payConfig['mch_id']);
        if ($payConfig['type'] == 'server') {
            $config->SetSubMchID($payConfig['sub_mch_id']);
        }
        $config->SetKey($payConfig['key']);
        $config->SetSignType('HMAC-SHA256');

        $WxPayApi = new WxPayApi();
        $WxPayApi->closeOrder($config, $input);

        $this->wxpayFail($out_trade_no, ['return_msg' => '支付失败，已取消']);
    }

    private function getRunTime()
    {
        $ntime = microtime(true);
        $total = $ntime - $GLOBALS['_beginTime'];
        return round($total, 4);
    }


    private function wxpaySuccess($out_trade_no, $payConfig, $shop, $result)
    {
        // 优惠信息
        $settlement_total_fee = $result['total_fee'];
        $coupon_count = 0;
        $coupon_fee_nocash = 0;
        $coupon_fee_cash = 0;
        if (!empty($result['coupon_count'])) {
            if ($result['coupon_type_0'] == 'NO_CASH') {
                $coupon_fee_nocash = $result['coupon_fee_0'];
            }
            if ($result['coupon_type_0'] == 'CASH') {
                $coupon_fee_cash = $result['coupon_fee_0'];
            }
            if ($result['coupon_type_1'] == 'NO_CASH') {
                $coupon_fee_nocash = $result['coupon_fee_1'];
            }
            if ($result['coupon_type_1'] == 'CASH') {
                $coupon_fee_cash = $result['coupon_fee_1'];
            }
            if (empty($coupon_fee_cash) && empty($coupon_fee_nocash)) {
                $coupon_fee_cash = $result['coupon_fee_0'];
            }
            $coupon_count = $result['coupon_count'];
            if (isset($result['settlement_total_fee'])) {
                $settlement_total_fee = $result['settlement_total_fee'];
            }

        }
        //营销详情
        if (!empty($result['promotion_detail'])) {
            $promotion_detail = json_decode($result['promotion_detail'], true);
            $coupon_count = count($promotion_detail['promotion_detail']);
            foreach ($promotion_detail['promotion_detail'] as $k => $v) {
                if ($v['type'] == 'DISCOUNT') {
                    $coupon_fee_nocash += ($v['amount'] * 100);
                } else {
                    $coupon_fee_cash += ($v['amount'] * 100);
                }
            }
            $settlement_total_fee = $result['total_fee'] * 100 - $coupon_fee_nocash;
        }
        // 计算手续费
        $fee = $this->calcOrderFee($payConfig['rate'], $settlement_total_fee / 100);
        // 计算代理分润
        if ($shop['agent_id'] && $fee > 0) {
            $rebate = Db::name('agent')
                ->where('id', $shop['agent_id'])
                ->value('rebate');
            $fee_agent = $this->calcAgentFee($payConfig['rate'], $settlement_total_fee / 100, intval($rebate));
        } else {
            $fee_agent = 0;
        }

        Db::name('order')
            ->where('out_trade_no', $out_trade_no)
            ->update([
                'status' => 1,
                'transaction_id' => $result ['transaction_id'],
                'coupon_count' => $coupon_count,
                'coupon_fee_nocash' => $coupon_fee_nocash,
                'coupon_fee_cash' => $coupon_fee_cash,
                'settlement_total_fee' => $settlement_total_fee,
                'fee' => $fee * 100,
                'fee_agent' => $fee_agent * 100,
                'pay_time' => strtotime($result['time_end'])
            ]);

        return successJson('收款成功');
    }

    /**
     * 支付失败
     */
    private function wxpayFail($out_trade_no, $result = [])
    {
        Db::name('order')
            ->where('out_trade_no', $out_trade_no)
            ->update([
                'status' => 2
            ]);
        if (!empty($result)) {
            return errorJson($result['return_msg']);
        } else {
            return errorJson('收款失败，请重试');
        }
    }

    /**
     * 创建订单号
     */
    private function createOrderNo($pay_type)
    {
        if ($pay_type == 'alipay') {
            return 'A' . date('YmdHis') . rand(1000, 9999);
        } else {
            return 'W' . date('YmdHis') . rand(1000, 9999);
        }
    }

}
